Skip to main content

第22章 位运算

位运算是指对二进制数的各个位进行操作的运算,它直接作用于数据的二进制位,具有运算速度快、效率高的特点,在计算机底层编程、数据压缩、加密算法等领域有着广泛的应用。

22.1 位运算的基本概念

位运算的操作对象是整数的二进制表示形式,这里的整数包括signed(有符号)和unsigned(无符号)类型。在进行位运算时,忽略整数的符号位(对于有符号数),仅对各个二进制位进行逻辑或算术操作。 例如,对于整数5(二进制为00000101)和3(二进制为00000011),位运算将直接对这两个二进制数的每一位进行操作。

22.2 常用的位运算符

22.2.1 按位与(&)

运算规则:两个二进制位都为1时,结果位为1;否则为0。 0&0=0; 0&1=0; 1&0=0; 1&1=10 \& 0=0;\ 0 \& 1=0;\ 1 \& 0=0;\ 1 \& 1=1 示例: 5(00000101)&3(00000011)=1(00000001)5(00000101) \& 3(00000011) = 1(00000001) 计算过程:逐位进行与运算,第1位 1&1=11 \& 1=1,其余位运算结果全为0。

应用:

  1. 清零:a & 0,所有位置0;
  2. 截取指定位:a & 0x0F 取出低4位。

22.2.2 按位或(|)

运算规则:两个二进制位至少有一个为1,结果位为1;否则为0。 00=0; 01=1; 10=1; 11=10 | 0=0;\ 0 | 1=1;\ 1 | 0=1;\ 1 | 1=1 示例: 5(00000101)3(00000011)=7(00000111)5(00000101) | 3(00000011) = 7(00000111)

应用:置位,将指定二进制位设为1,如a | (1 << 3)把第3位改为1。

22.2.3 按位异或(^)

运算规则:两位不同则为1,相同则为0。 00=0; 01=1; 10=1; 11=00 \wedge 0=0;\ 0 \wedge 1=1;\ 1 \wedge 0=1;\ 1 \wedge 1=0 示例: 5(00000101)3(00000011)=6(00000110)5(00000101) \wedge 3(00000011) = 6(00000110)

应用:

  1. 翻转掩码对应二进制位:a ^ 0x0F翻转低4位;
  2. 不借助临时变量交换两个整数:
a = a ^ b;
b = a ^ b;
a = a ^ b;

22.2.4 按位取反(~)

运算规则:所有二进制位0变1、1变0。 示例:~5 在32位系统结果为0xFFFFFFFA,数学公式:~a = -a - 1。 应用:生成全1掩码。

22.2.5 左移

规则:二进制整体左移N位,高位丢弃,低位补0。 示例:5(00000101)<<2=20(00010100)5(00000101) << 2 = 20(00010100) 特性:正数/无符号数左移N位等价乘以2N2^N(无溢出前提下)。

22.2.6 右移

分两种类型:

  1. 无符号unsigned:逻辑右移,低位丢弃,高位补0;
  2. 有符号signed:算术右移,低位丢弃,高位补符号位(正数补0,负数补1)。 示例: 无符号8>>2=28 >> 2 = 2; 8位有符号8(11111000)>>2=2(11111110)-8(11111000) >> 2 = -2(11111110); 特性:正数/无符号右移N位等价除以2N2^N(向下取整)。

22.3 异或交换变量

#include <stdio.h>
int main(){
int a=5,b=10;
printf("交换前:a=%d,b=%d\n",a,b);
a = a ^ b;
b = a ^ b;
a = a ^ b;
printf("交换后:a=%d,b=%d\n",a,b);
return 0;
}

注意:两个变量不能是同一块内存,否则会全部置0。

22.4 位运算符优先级(从高到低)

~ > << >> > & > ^ > | 复杂表达式建议括号明确运算顺序,避免歧义。 示例:

int a=5,b=3;
int c = a & b | 1; // 先算&
int d = a & (b | 1);// 先算|

22.5 位运算应用场景

  1. 嵌入式硬件寄存器位控制;
  2. 图像RGB通道提取;
  3. 高效判断奇偶:(a & 1) == 1
  4. 快速求2的幂:1 << n
  5. 加密、压缩底层二进制处理。

22.6 使用注意事项

  1. 有符号数右移会补符号位,逻辑操作优先用unsigned
  2. 左移溢出结果未定义;
  3. 位运算可读性差,必须加注释;
  4. 32/64位系统int长度不同,跨平台注意位数差异。